package com.example.userserver.util;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.commons.entity.UserDO;
import com.example.commons.utils.ExceptionEnum;
import com.example.commons.utils.JinZhiException;
import com.example.commons.vo.TokenVO;
import com.example.userserver.config.JwtConfigTime;
import com.example.userserver.config.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

/**
 * <pre>
 * jwt工具类
 * </pre>
 *
 * <small> 2018年4月28日 | Aron</small>
 */
@Slf4j
@Component
public class JWTUtil {

    private static JWTConfigProperties jwtConfigProperties = null;
    public final static String userPrimaryKey = SpringContextHolder.getBean(JWTConfigProperties.class).getUserPrimaryKey();

    @PostConstruct
    public void init() {
        jwtConfigProperties = SpringContextHolder.getBean(JWTConfigProperties.class);
    }

    public static String STR_DELIMITER = "\\.";
    public static int LEVEL = 3;

    /**
     * token是否过期
     *
     * @return true：过期
     */
    public static boolean isTokenExpired(String token) {
        Date now = Calendar.getInstance().getTime();
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getExpiresAt().before(now);
    }

    /**
     * <pre>
     * </pre>
     *
     * <small> 2018年4月28日 | Aron</small>
     *
     * @param token  即jwt
     * @param userId 用户id
     * @param secret 用户的secret
     */
    public static void verify(String token, String userId, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withClaim(jwtConfigProperties.getUserPrimaryKey(), userId).build();
            verifier.verify(token);
        } catch (TokenExpiredException exception) {
            log.info("token 签名校验失败,过期：{}", token);
            throw new JinZhiException(ExceptionEnum.TOKENFIAL.getStatus(),ExceptionEnum.TOKENFIAL.getMessage());
        } catch (InvalidClaimException exception2) {
            log.info("token 签名校验失败,数据异常：{}", token);
            throw new JinZhiException(ExceptionEnum.TOKENFIAL.getStatus(),ExceptionEnum.TOKENFIAL.getMessage());
        } catch (Exception exception3) {
            log.info("token 签名校验失败：{}", token);
           // throw new IFastApiException(EnumErrorCode.apiAuthorizationInvalid.getCodeStr());
            throw new JinZhiException(ExceptionEnum.TOKENFIAL.getStatus(),ExceptionEnum.TOKENFIAL.getMessage());
        }
    }

    public static void verify(String token, String userId, String secret, boolean isRefreshToken) {
        if (isRefreshToken) {
            secret += "_REFRESH_TOKEN";
        }
        verify(token, userId, secret);
    }

    /**
     * <pre>
     * 获得token中的信息无需secret解密也能获得
     * </pre>
     *
     * <small> 2018年4月28日 | Aron</small>
     *
     * @param token token
     */
    public static String getWxUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            Claim claim = jwt.getClaim(userPrimaryKey);
            return claim.asString();
        } catch (JWTDecodeException e) {
            log.warn("token解码获取{}失败：{}",userPrimaryKey, token);
            return null;
        }
    }

    /**
     * <pre>
     * </pre>
     *
     * <small> 2018年4月28日 | Aron</small>
     *
     * @param secret 加密密钥
     * @param expire 有效期，毫秒值
     */
    public static String jzSign(UserDO userDO, String secret,Long expire) {
        // 过期时间
        final Calendar instance = Calendar.getInstance();
        //设置过期时间
        instance.add(Calendar.SECOND, expire.intValue());

        try {
            final String token;
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 以abc为密钥进行hmac256方法加密，保存 a,b两个属性

            token = JWT.create().withHeader(new HashMap<>())
                    .withClaim("username", userDO.getName())
                    .withClaim("userId", userDO.getId())
                    .withClaim("mobile", userDO.getMobile())
                    .withClaim("name", userDO.getName())
                    .withClaim("orgName", userDO.getOrgName())
                    .withClaim("orgId", userDO.getOrgId())
                    .withClaim("salt", userDO.getSalt())
                    .withExpiresAt(instance.getTime())
                    .sign(algorithm);
            return token;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return null;

    }

    /**
     * <pre>
     * </pre>
     *
     * <small> 2018年4月28日 | Aron</small>
     *
     * @param userId 用户标识
     * @param secret 加密密钥
     * @param expire 有效期，毫秒值
     */
    public static String sign(String userId, String secret,Long expire) {
        // 过期时间
        final Calendar instance = Calendar.getInstance();
        //设置过期时间
        instance.add(Calendar.SECOND, JwtConfigTime.time5);

        try {
            final String token;
            Algorithm algorithm = Algorithm.HMAC256(secret);
            // 以abc为密钥进行hmac256方法加密，保存 a,b两个属性

            token = JWT.create().withHeader(new HashMap<>())
                    .withClaim("a", "ccc")
                    .withClaim("b", JSONObject.toJSON(Arrays.asList("a", "b", "c")).toString())
                    .withExpiresAt(instance.getTime())
                    .sign(algorithm);
            return token;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
       return null;
    }

    /**
     *   .withClaim("username", userDO.getName())
     *                     .withClaim("userId", userDO.getId())
     *                     .withClaim("mobile", userDO.getMobile())
     *                     .withClaim("name", userDO.getName())
     *                     .withClaim("orgName", userDO.getOrgName())
     *                     .withClaim("orgId", userDO.getOrgId())
     *                     .withClaim("salt", userDO.getSalt())
     * @param token
     * @param secret
     * @return
     */
    public static UserDO jzVerify(String token, String secret) {
        UserDO userDO=new UserDO();
        JWTVerifier build = null;
        try {
            build = JWT.require(Algorithm.HMAC256(secret)).build();
            final DecodedJWT verify = build.verify(token);
            // 取出a
            userDO.setName( verify.getClaim("salt").asString());
            userDO.setMobile( verify.getClaim("mobile").asString());
            userDO.setName( verify.getClaim("name").asString());
            userDO.setOrgName( verify.getClaim("orgName").asString());
            userDO.setOrgId( verify.getClaim("orgId").asLong());
            userDO.setSalt( verify.getClaim("salt").asString());
            // 取出过期时间
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }


        return userDO;
    }

    /**
     * <pre>
     * </pre>
     *
     * <small> 2018年4月28日 | Aron</small>
     *
     * @param userId 用户标识
     * @param secret 加密密钥
     * @param expire 有效期，毫秒值
     */
    public static String sign(String userId, String secret, long expire, boolean isRefreshToken) {
        if (isRefreshToken) {
            secret += "_REFRESH_TOKEN";
        }
        return sign(userId, secret, expire);
    }
}
